package com.typhoon.rpc.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.typhoon.rpc.common.codec.RpcDecoder;
import com.typhoon.rpc.common.codec.RpcEncoder;
import com.typhoon.rpc.common.dto.RpcRequest;
import com.typhoon.rpc.common.dto.RpcResponse;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class RpcClient extends SimpleChannelInboundHandler<RpcResponse> {
	  private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class);

	    private final String host;
	    private final int port;

	    private RpcResponse response;

	    public RpcClient(String host, int port) {
	        this.host = host;
	        this.port = port;
	    }

	    @Override
	    public void channelRead0(ChannelHandlerContext ctx, RpcResponse response) throws Exception {
	        this.response = response;
	    }

	    @Override
	    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
	        LOGGER.error("api caught exception", cause);
	        ctx.close();
	    }

	    public RpcResponse send(RpcRequest request) throws Exception {
	        EventLoopGroup group = new NioEventLoopGroup();
	        try {
	            // 创建并初始化 Netty 客户端 Bootstrap 对象
	            Bootstrap bootstrap = new Bootstrap();//创建客户端启动器
	            bootstrap.group(group);//设置工作组
	            bootstrap.channel(NioSocketChannel.class);//设置channel生成方式,异步channel
	            bootstrap.handler(new ChannelInitializer<SocketChannel>() {//指定channelHandler
	                @Override
	                public void initChannel(SocketChannel channel) throws Exception {
	                    ChannelPipeline pipeline = channel.pipeline();
	                    pipeline.addLast(new RpcEncoder(RpcRequest.class)); // 编码 RPC 请求
	                    pipeline.addLast(new RpcDecoder(RpcResponse.class)); // 解码 RPC 响应
	                    pipeline.addLast(RpcClient.this); // 处理 RPC 响应
	                }
	            });
	            bootstrap.option(ChannelOption.TCP_NODELAY, true);//设置channel全局配置
	            // 连接 RPC 服务器
	            ChannelFuture future = bootstrap.connect(host, port).sync();//连接服务器并同步等待执行结果
	            // 写入 RPC 请求数据并关闭连接
	            Channel channel = future.channel();//从future获取一个channel
	            channel.writeAndFlush(request).sync();//将请求数据写入channel中:先使用RpcEncoder进行编码
	            channel.closeFuture().sync();//同步断开连接
	            // 返回 RPC 响应对象
	            return response;//会调用channelRead0方法将查询结果放入Response中
	        } finally {
	            group.shutdownGracefully();//优雅关闭客户端
	        }
	    }
}
